package com.example.springstatemachine.service;

import com.example.springstatemachine.consant.DocumentEvents;
import com.example.springstatemachine.consant.DocumentStates;
import com.example.springstatemachine.model.Action;
import com.example.springstatemachine.model.Document;
import com.example.springstatemachine.model.DocumentState;
import com.example.springstatemachine.repository.ActionRepository;
import com.example.springstatemachine.repository.DocumentRepository;
import com.example.springstatemachine.repository.DocumentStateRepository;
import com.example.springstatemachine.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.stereotype.Service;

@Service
public class DocumentService {

    private final StateMachine<DocumentStates, DocumentEvents> stateMachine;
    private final DocumentRepository documentRepository;
    private final DocumentStateRepository documentStateRepository;
    private final ActionRepository actionRepository;
    private final UserRepository userRepository;

    @Autowired
    public DocumentService(StateMachine<DocumentStates, DocumentEvents> stateMachine,
                           DocumentRepository documentRepository,
                           DocumentStateRepository documentStateRepository,
                           ActionRepository actionRepository,UserRepository userRepository) {
        this.stateMachine = stateMachine;
        this.documentRepository = documentRepository;
        this.documentStateRepository = documentStateRepository;
        this.actionRepository = actionRepository;
        this.userRepository = userRepository;
    }

    public String submitDocument(Long documentId, Long userId) {
        Document document = documentRepository.findById(documentId).orElseThrow(() -> new RuntimeException("Document not found"));
        stateMachine.sendEvent(DocumentEvents.SUBMIT);

        // Record the state change
        DocumentState documentState = new DocumentState();
        documentState.setDocument(document);
        documentState.setState(stateMachine.getState().getId().name());
        documentState.setEvent(DocumentEvents.SUBMIT.name());
        documentStateRepository.save(documentState);

        // Record the action
        Action action = new Action();
        action.setDocument(document);
        action.setUser(userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found")));
        action.setAction(DocumentEvents.SUBMIT.name());
        actionRepository.save(action);

        return "Document submitted. Current state: " + stateMachine.getState().getId();
    }

    // Similar methods for approve, reject, and publish

    public String approveDocument(Long documentId, Long userId) {
        Document document = documentRepository.findById(documentId).orElseThrow(() -> new RuntimeException("Document not found"));
        stateMachine.sendEvent(DocumentEvents.APPROVE);

        // Record the state change
        DocumentState documentState = new DocumentState();
        documentState.setDocument(document);
        documentState.setState(stateMachine.getState().getId().name());
        documentState.setEvent(DocumentEvents.APPROVE.name());
        documentStateRepository.save(documentState);

        // Record the action
        Action action = new Action();
        action.setDocument(document);
        action.setUser(userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found")));
        action.setAction(DocumentEvents.APPROVE.name());
        actionRepository.save(action);

        return "Document approved. Current state: " + stateMachine.getState().getId();
    }

    public String rejectDocument(Long documentId, Long userId) {
        Document document = documentRepository.findById(documentId).orElseThrow(() -> new RuntimeException("Document not found"));
        stateMachine.sendEvent(DocumentEvents.REJECT);

        // Record the state change
        DocumentState documentState = new DocumentState();
        documentState.setDocument(document);
        documentState.setState(stateMachine.getState().getId().name());
        documentState.setEvent(DocumentEvents.REJECT.name());
        documentStateRepository.save(documentState);

        // Record the action
        Action action = new Action();
        action.setDocument(document);
        action.setUser(userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found")));
        action.setAction(DocumentEvents.REJECT.name());
        actionRepository.save(action);

        return "Document rejected. Current state: " + stateMachine.getState().getId();
    }

    public String publishDocument(Long documentId, Long userId) {
        Document document = documentRepository.findById(documentId).orElseThrow(() -> new RuntimeException("Document not found"));
        stateMachine.sendEvent(DocumentEvents.PUBLISH);

        // Record the state change
        DocumentState documentState = new DocumentState();
        documentState.setDocument(document);
        documentState.setState(stateMachine.getState().getId().name());
        documentState.setEvent(DocumentEvents.PUBLISH.name());
        documentStateRepository.save(documentState);

        // Record the action
        Action action = new Action();
        action.setDocument(document);
        action.setUser(userRepository.findById(userId).orElseThrow(() -> new RuntimeException("User not found")));
        action.setAction(DocumentEvents.PUBLISH.name());
        actionRepository.save(action);

        return "Document published. Current state: " + stateMachine.getState().getId();
    }
}